package gbench.sandbox.neo4j.draft;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import gbench.common.matlib.MatlibCanvas.NVec;
import gbench.common.matlib.data.DataReader.DFrame;
import static gbench.common.matlib.MatlibCanvas.*;
import gbench.common.tree.LittleTree;
import gbench.common.tree.LittleTree.IRecord;
import gbench.common.tree.LittleTree.Json;
import gbench.commonApp.jdbc.Neo4jApp;
import org.junit.jupiter.api.Test;

import static gbench.common.tree.LittleTree.MFT;
import static gbench.common.tree.LittleTree.IRecord.*;
import static gbench.common.tree.LittleTree.SimpleRecord.REC2;

/**
 * 二元关系 示例：这就是对关系型数据库的模式演练
 * @author gbench
 *
 */
public class MyHospital {
    
    @Test
    public void foo() {
        
//        Neo4jApp.updateAnnotaion(Neo4jApp.Database.class, JdbcConfig.class, 
//            "url", "jdbc:neo4j:bolt://localhost/mydb2?nossl","user", "neo4j","password", "123456");
        final var neo4jApp = Neo4jApp.newInstance("",null,null); // 创建图的应用App
        final var ai = new AtomicInteger(0);
        neo4jApp.set_intialize_handler(g->{// 把交易代码也写入到边明路径中。
            final var p = g.getEdge_name_renderer();// 记录老的边名记录器
            g.setEdge_name_renderer(edge->p.apply(edge)+"_"+edge.attr("transcode",ai.getAndIncrement()));// 在边实体记录中增加transcode 
            if(true)g.setAttr_ops((attributeSets,rec)->{ // 自定义 属性设置函数,使得可以设置复杂数据类型以及对弈同一键赋予多个值
                final var key = rec.str("key"); // 边名/顶点名 
                final var name = rec.str("name"); // 属性名 
                final var value = rec.get("value", e -> (e instanceof IRecord)
                        ? ((IRecord) e).json().replace("\"", "\\\"")
                        : e != null && !e.getClass().isPrimitive() && ! (e instanceof String)
                            ? LittleTree.trycatch(obj->Json.obj2json(obj).replace("\"", "\\\"")).apply(e)
                            : e);// 属性值
                final var as = attributeSets.compute(key,(k,v)->(v==null?REC():v));
                as.compute(name, v->{
                    if(v==null) {
                        return value;
                    }else {
                        final var ll = as.pathL(name);
                        if(!ll.contains(value))ll.add(value);
                        return ll;
                    }//if
                });// compute
            });// setAttr_ops
        },false);// 注释intialize_handler 采用增量覆盖的方式 即replace 参数使用false
        
        // 双顶点二元关系 模式
        final var purchaseProto = REC( "0#vlblk","User:Person", "1#vlblk","Product", "elblk","Purchase",// 基本的买卖关系对象
                "createtime",new Date(),"shop","华联超市");// 买卖关系
        final var secreteProto = REC( "0#vlblk","Cell", "1#vlblk","Molecule", "elblk","Secrete",// 基本的买卖关系对象
                "createtime",new Date(),"system","免疫系统");// 买卖关系
        final var symptomProto = REC( "0#vlblk","症状", "1#vlblk","病原微生物",// 基本的买卖关系对象
                "createtime",new Date(),"name","病因");// 买卖关系
        final var profileProto = REC("0#vlblk","Entity");// 摘要信息
        
        // 构建数据关系图
        final var g = neo4jApp.graph(REC2( // 交易的事务记录
            // 采购关系
            "张三/苹果", purchaseProto.derive("transcode",ai.getAndIncrement(),"quality",3,"unit","斤","0#friend","王五")// 张三买了3斤苹果
            ,"张三/苹果", purchaseProto.derive("transcode",ai.getAndIncrement(),"quality",3,"unit","斤","0#friend","王五")// 张三买了3斤苹果
            ,"张三/苹果", purchaseProto.derive("transcode",ai.getAndIncrement(),"quality",3,"unit","斤","0#friend","王五")// 张三买了3斤苹果
            ,"张三/苹果", purchaseProto.derive("transcode",ai.getAndIncrement(),"quality",3,"unit","斤","0#friend","王五")// 张三买了3斤苹果
            ,"张三/苹果", purchaseProto.derive("transcode",ai.getAndIncrement(),"quality",30,"unit","斤","0#friend","王五")// 张三买了3斤苹果
            
            //分泌
            ,"恶性肥大细胞/CD9",secreteProto.derive("transcode",ai.getAndIncrement())
            ,"恶性肥大细胞/CD33",secreteProto.derive("transcode",ai.getAndIncrement())
            ,"恶性肥大细胞/CD44",secreteProto.derive("transcode",ai.getAndIncrement())
            ,"恶性肥大细胞/CDll7",secreteProto.derive("transcode",ai.getAndIncrement())
            
            //症状学
            ,"发热/细菌",symptomProto.derive("transcode",ai.getAndIncrement(),"elblk","病因","category","感染性发热")
            ,"发热/病毒",symptomProto.derive("transcode",ai.getAndIncrement(),"elblk","病因","category","感染性发热")
            ,"发热/支原体",symptomProto.derive("transcode",ai.getAndIncrement(),"elblk","病因","category","感染性发热")
            ,"发热/立克次体",symptomProto.derive("transcode",ai.getAndIncrement(),"elblk","病因","category","感染性发热")
            ,"发热/螺旋体",symptomProto.derive("transcode",ai.getAndIncrement(),"elblk","病因","category","感染性发热")
            ,"发热/真菌",symptomProto.derive("transcode",ai.getAndIncrement(),"elblk","病因","category","感染性发热")
            ,"发热/寄生虫",symptomProto.derive("transcode",ai.getAndIncrement(),"elblk","病因","category","感染性发热")
            
            ,"发热/手术",symptomProto.derive("transcode",ai.getAndIncrement(),"1#vlblk","损伤","elblk","病因","category","非感染性发热")
            ,"发热/内出血",symptomProto.derive("transcode",ai.getAndIncrement(),"1#vlblk","损伤","elblk","病因","category","非感染性发热")
            ,"发热/大血肿",symptomProto.derive("transcode",ai.getAndIncrement(),"1#vlblk","损伤","elblk","病因","category","非感染性发热")
            ,"发热/大面积烧伤",symptomProto.derive("transcode",ai.getAndIncrement(),"1#vlblk","损伤","elblk","病因","category","非感染性发热")
            ,"发热/心脏",symptomProto.derive("transcode",ai.getAndIncrement(),"1#vlblk","器官","elblk","病因","category","非感染性发热","类型","栓塞")
            ,"发热/肺",symptomProto.derive("transcode",ai.getAndIncrement(),"1#vlblk","器官","elblk","病因","category","非感染性发热","类型","栓塞")
            ,"发热/脾",symptomProto.derive("transcode",ai.getAndIncrement(),"1#vlblk","器官","elblk","病因","category","非感染性发热","类型","栓塞")
            
            ,"心脏",profileProto.derive("$心率",REC("min",45,"max",60))
            
        ));// 交易数据库
        
        System.out.println(g);
        if(System.currentTimeMillis()>0) Neo4jApp // 过滤标记
        .getJdbc().withTransaction(sess->{// 查看买卖关系
            sess.sqlexecute("match (a)-[e]->(b) delete a,e,b");//删除表
            sess.sqlexecute(MFT("create {0}",g));// 创建数据表
            final var sql = "match (a)-[e]->(b) return a,e,b";// 查询表
            System.out.println(sql);
            var mm = sess.sql2records(sql);
            final var df = mm.stream().collect(DFrame.dfmclc);
            println("id","---->",df.eval(r->r.pathS("e",IRecord::REC).map(e->e.dbl("quality",0d)).collect(NVec.nveclc())).sum());
            mm.stream().filter(e->null!=e.pathO("b/心率")).forEach(e->{
                println("b/心率",e.pathR("b/心率"));
                println("b/vlblk",e.pathT("b/vlblk","-")); // 提取默认值
                println("e/createtime",e.pathT("e/createtime",LocalDateTime.class)); // 提取默认值
            });
            
            sess.sqlexecute("match p = (a)-[e]->(b) foreach ( n in nodes(p) | set n.marked=TRUE )");// 更新顶点数据:设置标记
            sess.sqlexecute("match p = (a)-[e]->(b) foreach ( n in nodes(p) | set n:db2)");// 更新顶点数据:设置标记
            System.out.println(FMT(mm=sess.sql2records(sql)));
            System.out.println(FMT(mm));
            final var rec = mm.get(0);
            System.out.println(rec.pathL("a/_labels"));
        });// withTransaction
        
        // 产看边属性
        //g.getAttributeSets().forEach((k,v)->System.out.println(k+"-->"+v));
    }// foo
}
